package org.example.security;

import lombok.extern.slf4j.Slf4j;
import org.example.service.UserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

import javax.annotation.Resource;

@Configuration
@Slf4j
public class SecurityConfiguration {

    @Resource
    private UserService userService;

    //新增验证加密密码
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public AuthenticationProvider authenticationProvider(){
        return new AuthenticationProvider() {
            @Override //自己实现认证过程
            public Authentication authenticate(Authentication authentication) throws AuthenticationException {
                //从认证对象中获取用户名，密码
                String username = authentication.getName();
                String password = authentication.getCredentials().toString();
                UserDetails user = userService.loadUserByUsername(username);
                //if (password.equals(user.getPassword())){
                if(passwordEncoder().matches(password,user.getPassword())){
                    log.info("Access success "+user.toString());
                    //匹配成功构建一个UsernamePasswordAuthenticationToken并返回
                    return new UsernamePasswordAuthenticationToken(username, password, user.getAuthorities());
                }else {
                    // 密码匹配失败
                    log.error("Access Denied: The username or password is wrong!");
                    throw new BadCredentialsException("The username or password is wrong!");
                }
            }

            @Override
            public boolean supports(Class<?> authentication) {
                return authentication.equals(UsernamePasswordAuthenticationToken.class);
            }
        };
    }

    /*基于基础认证模式*/
//    @Bean
//    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
//        // 禁用session会话 ，本质变为无状态而已，不创建session也不使用
//        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//
//        // 所有请求都需要认证，认证方式：httpBasic
//        http.authorizeHttpRequests((auth) -> {
//            auth.anyRequest().authenticated();
//        }).httpBasic(Customizer.withDefaults());
//
//        return http.build();
//    }


    //表单认证模式
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        // 启用session会话
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);

        // 认证方式：Form
        http.authorizeRequests()
                // 所有请求都需要认证
                .anyRequest().authenticated()
                .and()
                // 启动表单认证模式
                .formLogin()
                // 登录页面
                .loginPage("/login.html")
                // 请求提交地址
                .loginProcessingUrl("/check_login")
                // 放行上面的两个地址
                .permitAll()
                // 设置提交的参数名
                .usernameParameter("username")
                .passwordParameter("password")
                .and()
                // 开始设置注销功能
                .logout()
                // 注销的url
                .logoutUrl("/logout")
                // session直接过期
                .invalidateHttpSession(true)
                // 清除认证信息
                .clearAuthentication(true)
                // 注销成功后跳转地址
                .logoutSuccessUrl("/login.html")
                .and()
                // 禁用csrf安全防护
                .csrf().disable();

        return http.build();
    }

}
